//! \file PathSearch.h
//! \brief Defines the <code>fullsail_ai::algorithms::PathSearch</code> class interface.
//! \author Cromwell D. Enage
#ifndef _FULLSAIL_AI_PATH_PLANNER_ALGORITHMS_PATH_SEARCH_H_
#define _FULLSAIL_AI_PATH_PLANNER_ALGORITHMS_PATH_SEARCH_H_

#include "../Core/Tile.h"
#include "../Core/TileMap.h"
#include <vector>
#include <deque>
#include <map>
#include <math.h>
#include "../Core/PriorityQueue.h"

namespace fullsail_ai { namespace algorithms
{
	struct PlannerNode
	{
		// Members
		PlannerNode *parent;
		Tile *state;
		double heuristicCost;
		double givenCost;
		double finalCost;

		// Functions
		PlannerNode(Tile *node)
		{ 
			parent = NULL;
			state = node;
			heuristicCost = 0;
			givenCost = 0;
			finalCost = 0;
		}
		double CalcDistance(Tile *start, Tile*goal)
		{
			double distance = 0;
			double xCoord = goal->getXCoordinate() - start->getXCoordinate();
			xCoord *= xCoord;
			double yCoord = goal->getYCoordinate() - start->getYCoordinate();
			yCoord *= yCoord;
			distance = sqrt((xCoord+yCoord));
			return distance;
		}
		void CalcHeuristicCost(Tile *start, Tile *goal)
		{
			heuristicCost = CalcDistance(start, goal);
		}
		double CalcNewGivenCost(PlannerNode *current, PlannerNode *successor)
		{
			double newGivenCost = current->givenCost +
				CalcDistance(current->state, successor->state) * successor->state->getWeight();
			return newGivenCost;
		}
		// void CalcFinalCost()
	};

	bool NodeCompare(PlannerNode* const& first, PlannerNode* const& second);

	class PathSearch
	{
	private:
		Tile *m_Start;
		Tile *m_Goal;
		TileMap *m_TileMap;
		std::map<Tile*,PlannerNode*> m_CreatedList;
		PriorityQueue<PlannerNode*> m_OpenList;
		std::vector<const Tile*> m_SolutionPath;
		std::vector<PlannerNode*> m_Successors;
		bool m_SolutionFound;

		// Helper function to determine if 2 tiles are adjacent
		void areAdjacent(Tile *curTile, Tile *testTile);
		// Generates successors based on the current tile
		void generateSuccessos(Tile *curTile);

	public:
		//! \brief Default constructor.
		PathSearch();

		//! \brief Destructor.
		~PathSearch();

		//! \brief Sets the tile map.
		//!
		//! Invoked when the user opens a tile map file.
		//!
		//! \param   _tileMap  the data structure that this algorithm will use
		//!                    to access each tile's location and weight data.
		void initialize(TileMap* _tileMap);

		//! \brief Enters and performs the first part of the algorithm.
		//!
		//! Invoked when the user presses one of the play buttons.
		//!
		//! \param   startRow         the row where the start tile is located.
		//! \param   startColumn      the column where the start tile is located.
		//! \param   goalRow          the row where the goal tile is located.
		//! \param   goalColumn       the column where the goal tile is located.
		void enter(int startRow, int startColumn, int goalRow, int goalColumn);

		//! \brief Returns <code>true</code> if and only if no nodes are left open.
		//!
		//! \return  <code>true</code> if no nodes are left open, <code>false</code> otherwise.
		bool isDone() const;

		//! \brief Performs the main part of the algorithm until the specified time has elapsed or
		//! no nodes are left open.
		void update(long timeslice);

		//! \brief Returns an unmodifiable view of the solution path found by this algorithm.
		std::vector<Tile const*> const getSolution() const;

		//! \brief Resets the algorithm.
		void exit();

		//! \brief Uninitializes the algorithm before the tile map is unloaded.
		void shutdown();
	};
}}  // namespace fullsail_ai::algorithms

#endif  // _FULLSAIL_AI_PATH_PLANNER_ALGORITHMS_PATH_SEARCH_H_

